import json
import re

from django import http
from django.contrib.auth import login, logout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.cache import cache

from django.http import HttpResponseForbidden
from django.http import JsonResponse
from django.shortcuts import render, redirect
# Create your views here.
from django.urls import reverse
from django.views import View
from django_redis import get_redis_connection

from apps.ausers.models import User, Address, Area
from apps.ausers.utils import check_verify_email_token, generate_verify_email_url
from apps.carts.utils import merge_cart_cookie_to_redis
from apps.goods.models import SKU
from meiduo_mall.settings.dev import logger
from utils.response_code import RETCODE


class RegisterView(View):
    def get(self,request):
        '''提供注册页面'''


        return render(request, 'register.html')

    def post(self,request):
        '''实现用户注册'''
        username = request.POST.get('username')
        password = request.POST.get('password')
        password2 = request.POST.get('password2')
        mobile = request.POST.get('mobile')
        allow = request.POST.get('allow')
        sms_code = request.POST.get('msg_code')

        # 判断参数是否齐全
        if not all([username, password, password2, mobile, allow]):
            return http.HttpResponseForbidden('缺少必传参数')
        # 判断用户名是否是5-20个字符
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden('请输入5-20个字符的用户名')
        # 判断密码是否是8-20个数字
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseForbidden('请输入8-20位的密码')
        # 判断两次密码是否一致
        if password != password2:
            return http.HttpResponseForbidden('两次输入的密码不一致')
        # 判断手机号是否合法
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('请输入正确的手机号码')
        # 判断是否勾选用户协议
        if allow != 'on':
            return http.HttpResponseForbidden('请勾选用户协议')

        # 2.6 验证短信验证码是否正确;对比redis的值和前端的值
        from django_redis import get_redis_connection
        redis_code_client = get_redis_connection('sms_code')
        redis_code = redis_code_client.get("sms_%s" % mobile)

        if redis_code is None:
            return render(request, 'register.html', {'sms_code_errmsg': '无效的短信验证码'})

        if sms_code != redis_code.decode():
            return render(request, 'register.html', {'sms_code_errmsg': '输入短信验证码有误'})

        # 保存注册数据
        try:
            user=User.objects.create_user(username=username, password=password, mobile=mobile)
        except Exception as e:
            logger.info(e)
            return render(request, 'register.html', {'register_errmsg': '注册失败'})

        # 实现状态保持
        login(request, user)

        # 4.返回响应
        # return redirect('/')
        response = redirect(reverse('contents:index'))
        response.set_cookie('username', username, max_age=14 * 3600 * 24)
        return response



class UsernameCountView(View):
    def get(self,request,username):
        # *    1.接收用户名 username
        # *    2.校验判空 和 正则
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden('请输入5-20个字符的用户名')
        # *    3.逻辑数据库查询 User.objects.get(username=username).count()
        try:
            from apps.ausers.models import User
            count = User.objects.filter(username=username).count()
        except Exception as e:
            logger.error(e)
            return http.HttpResponseForbidden('不存在!')

        # *    4.返回给前端 json
        from utils.response_code import RETCODE
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': "查询成功", "count": count})

class MobileCountView(View):
    def get(self,request,mobile):
        # *    1.接收用户名 mobile
        # *    2.校验判空 和 正则
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', mobile):
            return http.HttpResponseForbidden('您输入的手机号格式不正确')
        try:
            from apps.ausers.models import User
            count = User.objects.filter(mobile=mobile).count()
        except Exception as e:
            logger.error(e)
            return http.HttpResponseForbidden('不存在!')

        # *    4.返回给前端 json
        from utils.response_code import RETCODE
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': "查询成功", "count": count})


class LoginView(View):
    """用户名登录"""

    def get(self, request):
        """
        提供登录界面
        :param request: 请求对象
        :return: 登录界面
        """
        return render(request, 'login.html')

    def post(self, request):
        """
        实现登录逻辑
        :param request: 请求对象
        :return: 登录结果
        """
        # 1.接收三个参数
        username = request.POST.get('username')
        password = request.POST.get('password')
        remembered = request.POST.get('remembered')

        # 2.校验参数
        if not all([username, password]):
            return HttpResponseForbidden('参数不齐全')
        # 2.1 用户名
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return HttpResponseForbidden('请输入5-20个字符的用户名')
        # 2.2 密码
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return HttpResponseForbidden('请输入8-20位的密码')

        # 3.验证用户名和密码--django自带的认证
        from django.contrib.auth import authenticate, login
        user = authenticate(username=username, password=password)

        if user is None:
            return render(request, 'login.html', {'account_errmsg': '用户名或密码错误'})

        # 4.保持登录状态
        login(request, user)



        # 5.是否记住用户名
        if remembered != 'on':
            # 不记住用户名, 浏览器结束会话就过期
            request.session.set_expiry(0)
        else:
            # 记住用户名, 浏览器会话保持两周
            request.session.set_expiry(None)

        # next 记录上一个页面的路由
        next = request.GET.get('next')
        if next:
            response = redirect(next)
        else:
            # 7. 跳转首页 index
            response = redirect(reverse('contents:index'))

        response.set_cookie('username', username, max_age=14 * 3600 * 24)
        # 合并购物车
        merge_cart_cookie_to_redis(request, user, response)
        return response


class LogoutView(View):
    """退出登录"""

    def get(self, request):
        """实现退出登录逻辑"""
        # 清理session
        logout(request)
        # 退出登录，重定向到登录页
        response = redirect(reverse('contents:index'))
        # 退出登录时清除cookie中的username
        response.delete_cookie('username')

        return response

# 6.用户中心
class UserInfoView(LoginRequiredMixin, View):
    """用户中心"""

    def get(self, request):
        """提供个人信息界面"""
        context = {
            'username': request.user.username,
            'mobile': request.user.mobile,
            'email': request.user.email,
            'email_active': request.user.email_active
        }
        return render(request, 'user_center_info.html', context=context)


# 添加邮箱后端逻辑实现
class EmailView(LoginRequiredMixin, View):
    """添加邮箱"""

    def put(self, request):
        """实现添加邮箱逻辑"""
        # 接收参数
        json_str = request.body.decode()
        json_dict = json.loads(json_str)
        email = json_dict.get('email')

        # 校验参数
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return http.HttpResponseForbidden('参数email有误')

        # 赋值email字段
        try:
            request.user.email = email
            request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '添加邮箱失败'})

        # 发送激活邮件
        verify_url = generate_verify_email_url(request.user)
        from celery_tasks.email.tasks import send_verify_email
        send_verify_email.delay(email, verify_url)

        # 响应添加邮箱结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '添加邮箱成功'})


# 7.激活邮箱
class VerifyEmailView(View):
    def get(self,request):
        # 接收参数
        token = request.GET.get('token')

        # 校验参数：判断token是否为空和过期，提取user
        if not token:
            return http.HttpResponseBadRequest('缺少token')

        user = check_verify_email_token(token)
        if not user:
            return http.HttpResponseForbidden('无效的token')

        # 修改email_active的值为True
        try:
            user.email_active = True
            user.save()
        except Exception as e:
            logger.error(e)
            return http.HttpResponseServerError('激活邮件失败')

        # 返回邮箱验证结果
        return redirect(reverse('users:info'))



class AreasView(View):
    def get(self,request):

        area_id=request.GET.get('area_id')

        if not area_id:
            province_list=cache.get('province_list')
            if not province_list:
                provinces=Area.objects.filter(parent__isnull=True)
                province_list=[{"id":pro.id,"name":pro.name} for pro in provinces]

                cache.set('province_list',province_list,3600)

            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'province_list': province_list})
        else:
            sub_data=cache.get("sub_data_"+area_id)
            if not sub_data:
                parent_model=Area.objects.get(id=area_id)
                subs=parent_model.subs.all()

                # 构建 前端的数据格式
                sub_list = [{"id": sub.id, "name": sub.name} for sub in subs]

                sub_data = {
                    'id': parent_model.id,
                    'name': parent_model.name,
                    'subs': sub_list
                }

                # 存缓存
                cache.set('sub_data_' + area_id, sub_data, 3600)
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'sub_data': sub_data})

class AddressView(View):
    def get(self,request):

        user=request.user
        addresses=Address.objects.filter(user=user,is_deleted=False)

        addresses_dict_list=[]
        for address in addresses:
            addresses_dict_list.append({
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            })

        context={
            'default_address_id': user.default_address_id,
            'addresses': addresses_dict_list,
        }

        return render(request,'user_center_site.html',context)

class CreateAddressView(View):
    def post(self,request):
        # count=Address.objects.filter(user=request.user, is_deleted=True).count()
        count=request.user.addresses.filter(is_deleted=True).count()

        if count>20:
            return  http.JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '超过地址数量上限'})

        json_dict=json.loads(request.body.decode())

        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        try:
            address=Address.objects.create(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )

            if not request.user.default_address:
                request.user.default_address=address
                request.user.save()

        except Exception as e:
            logger.info(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '新增地址失败'})

        # 4.构建前端的数据格式 字典{}
        address_dict = {
            "id": address.id,
            "title": address.receiver,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '新增地址成功', 'address': address_dict})

# 11. 修改和删除
class UpdateDestroyAddressView(LoginRequiredMixin, View):
    def put(self, request, address_id):
        # 1.接收参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # 2.校验 正则校验

        # 3. Address.objects.filter().update()
        try:
            Address.objects.filter(id=address_id).update(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '更新地址失败'})

        address=Address.objects.get(id=address_id)
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        # 响应更新地址结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '更新地址成功', 'address': address_dict})


    def delete(self,request,address_id):
        try:
            address=Address.objects.get(id=address_id)
            address.is_deleted=True
            address.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '删除地址失败'})

        # 响应删除地址结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '删除地址成功'})


class DefaultAddressView(View):
    def put(self,request,address_id):
        json_dict=json.loads(request.body.decode())
        title=json_dict.get('title')

        try:
            address=Address.objects.get(id=address_id)
            request.user.default_address=address
            request.user.save()

        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '设置默认地址失败'})

        # 响应设置默认地址结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '设置默认地址成功'})

class TitleAddressView(View):
    def put(self, request, address_id):
        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')

        try:
            address = Address.objects.get(id=address_id)
            address.title = title
            address.save()

        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '设置地址标题失败'})

        # 4.响应删除地址结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '设置地址标题成功'})


class ChangePwdView(View):
    def get(self,request):

        return render(request,'user_center_pass.html')

    def post(self,request):
        # 1.接收参数
        old_password=request.POST.get('old_pwd')
        new_password = request.POST.get('new_pwd')
        new_password2 = request.POST.get('new_cpwd')

        # 2. 校验 判空 判正则  是否一致

        # 3. 原始密码是否正确
        result=request.user.check_password(old_password)
        if not request:
            return render(request, 'user_center_pass.html', {'origin_pwd_errmsg': '原始密码错误'})

        # 4. 重置密码
        request.user.set_password(new_password)
        request.user.save()

        # 5. 清空状态, 删除cookie, 登录页
        logout(request)

        response=redirect(reverse('users:login'))
        response.delete_cookie("username")

        return response


class UserBrowseHistory(LoginRequiredMixin, View):
    """用户浏览记录"""

    def get(self, request):
        """获取用户浏览记录"""
        # 获取Redis存储的sku_id列表信息
        redis_conn = get_redis_connection('history')
        sku_ids = redis_conn.lrange('history_%s' % request.user.id, 0, -1)

        # 根据sku_ids列表数据，查询出商品sku信息
        skus = []
        for sku_id in sku_ids:
            sku = SKU.objects.get(id=sku_id)
            skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price
            })

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'skus': skus})

    def post(self, request):
        """保存用户浏览记录"""
        # 1.接收json参数
        sku_id = json.loads(request.body.decode()).get('sku_id')

        # 2.根据sku_id 查询sku
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return HttpResponseForbidden('商品不存在!')

        # 3.如果有sku,保存到redis
        history_redis_client = get_redis_connection('history')
        history_key = 'history_%s' % request.user.id

        redis_pipeline = history_redis_client.pipeline()
        # 3.1 去重
        history_redis_client.lrem(history_key, 0, sku_id)
        # 3.2 存储
        history_redis_client.lpush(history_key, sku_id)
        # 3.3 截取 5个
        history_redis_client.ltrim(history_key, 0, 4)
        redis_pipeline.execute()

        # 响应结果
        return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})